package com.tj.ocr.similar;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;

import javax.imageio.ImageIO;

import com.tj.ocr.img.BlankWhiteUtil;
import com.tj.ocr.img.ImageRW;
import com.tj.ocr.img.LinePop;
import com.tj.ocr.img.MyImage;
import com.tj.ocr.img.TextPop;
import com.tj.ocr.train.TrainMain;

public class TextSearcher implements Serializable {
    private static final long serialVersionUID = -1511439098518065680L;

    private static final int line_max = 1000;
	
	private List<Integer> winSizeList;
	private Map<Integer, Map<Integer, List<FingerPrint>>> fingerPrintList;

	@SuppressWarnings("unused")
    private static TextSearcher inst = new TextSearcher();

	private TextSearcher() {
		winSizeList = new ArrayList<>();
		fingerPrintList = new HashMap<>();
	}

	public static TextSearcher load(String path) {
		ObjectInputStream oin = null;
		try {
			oin = new ObjectInputStream(new FileInputStream(path));
			return (TextSearcher) oin.readObject(); // 没有强制转换到Person类型
		} catch (ClassNotFoundException | IOException e) {
			e.printStackTrace();
		}finally{
			if(oin != null)
				try {
					oin.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
		}
		
		return null;
	}

	public static TextSearcher create(String dataPath, int startLeftPos) {
		try {
			TextSearcher ts = new TextSearcher();
			TextPop.start_pos = startLeftPos;

			Map<Integer, String> names = new HashMap<>();
			Map<Integer, List<FingerPrint>> fingers = null;
			Map<Integer, Integer> sizeCount = new HashMap<>();

			File dir = new File(dataPath);
			if (dir.isDirectory()) {
				File[] fs = dir.listFiles();
				// build fingerPrint
				for (File file : fs) {
					String fname = file.getName();
					if(fname.endsWith("bin")) continue;
					
					BufferedImage bi = ImageIO.read(file);

					int width = bi.getWidth();
					if (ts.fingerPrintList.containsKey(width)) {
						sizeCount.put(width, sizeCount.get(width) + 1);
						fingers = ts.fingerPrintList.get(width);
					} else {
						sizeCount.put(width, 1);
						// winSizeList.add(width);
						fingers = new HashMap<Integer, List<FingerPrint>>();
						ts.fingerPrintList.put(width, fingers);
					}

					FingerPrint fp = FingerPrint.get(bi);
					fname = fname.substring(0, fname.length() - 4);

					if (fname.length() == 2)
						fname = fname.substring(1);
					fp.setText(fname);
					List<FingerPrint> ls = null;

					if (fingers.containsKey(fp.getId())) {
						ls = fingers.get(fp.getId());
						for (FingerPrint tf : ls) {
							if (tf.isSame(fp)) {
								System.out.println("exists:" + fp.getId() + "  file:" + file.getName());
								System.out.println("conflict:" + names.get(fp.getId()));
							}
						}
					} else {
						names.put(fp.getId(), file.getName());
						ls = new ArrayList<>();
					}
					ls.add(fp);
					fingers.put(fp.getId(), ls);
				}

				// sort size
				ts.sortSize(sizeCount);
			}

			try {
				FileOutputStream fs = new FileOutputStream(dataPath + "tsv1.bin");
				ObjectOutputStream os = new ObjectOutputStream(fs);
				os.writeObject(ts);
				os.close();
			} catch (Exception ex) {
				ex.printStackTrace();
			}
			
			return ts;
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}

	private void sortSize(Map<Integer, Integer> sizeCount) {
		List<Integer> ls = new ArrayList<>();

		for (Integer count : sizeCount.values()) {
			ls.add(count);
		}

		Collections.reverse(ls);
		for (int lz : ls) {
			Integer si = null;
			for (Integer key : sizeCount.keySet()) {
				if (sizeCount.get(key) == lz) {
					winSizeList.add(key);
					si = key;
					break;
				}
			}

			sizeCount.remove(si);
		}

	}

	public String doTextSearch(MyImage bi) {
		String ret = "";
		int start_pos = TextPop.start_pos;
		int pos = start_pos + bi.getFromx();
		int fromy = bi.getFromy();
		int width = bi.getWidth(), height = bi.getHeight();
		int ci = 0;
		while (ci++ < line_max) {
			boolean hasData = false;
			// slip one by one
			for (int w : winSizeList) {
				if (pos + w >= width)
					return ret;

				// slip image
				MyImage subi = TextPop.subImage(bi, pos, fromy, w, height);
				// ImageRW.write(subi.realImage(),
				// "d:\\test\\c1\\r"+w+ci+".png");
				// get fingerPrint
				FingerPrint fp = FingerPrint.getEx(subi, subi.getHeight());
				List<FingerPrint> fps = fingerPrintList.get(w).get(fp.getId());
				if (fps != null) {
					// check fingerPrint
					for (FingerPrint print : fps) {
						if (print.isSame(fp)) {
							ret += trans(print.getText());
							pos += w;
							hasData = true;
							break;
						}
					}

					if (hasData)
						break;
				}
			}

			if (hasData == false)
				pos++;
		}

		return ret;
	}

	private String trans(String text) {
		if(text == null)
			return "";
		
		if(text.length() == 1)
			return text;
		
		if(text.startsWith("b")){
			String t = text.substring(1);
			int indx = TrainMain.bd[0].indexOf(t);
			if(indx > -1){
				indx = indx / 3;
				return TrainMain.bd[1].substring(indx, indx+1);
			}
		}
		
		return "";
	}

	public static void main(String[] args) {
		TextSearcher ts = create("d:\\test\\out_m", 4);

		//TextSearcher ts = TextSearcher.load("d:\\test\\outtsv1.bin");
		// get text
		BufferedImage bi = ImageRW.read("d:\\test\\s1.png");
		MyImage mi = BlankWhiteUtil.procEx(bi, 170);

		LinePop lpop = new LinePop(mi);
		while ((mi = lpop.pop()) != null) {
			System.out.println(ts.doTextSearch(mi));
		}
		
		System.out.println("ok");
	}
}
